/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package mballs;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import javax.swing.JFrame;
import javax.imageio.*;

/**
 *
 * @author menderleit
 */
public class MBalls {

    // Our own double-buffer.
    public static class DBuffer extends DoubleBuffer {

        // Timer variables.
        private static PTimer pt;
        private static long difTime;

        // MetaBall thresholds.
        private static double MIN_T = 0.6;
        private static double MAX_T = 1.4;
        private static double MIN_THRESHOLD = 0.95;
        private static double MAX_THRESHOLD = 1.05;
        
        // Angle values for the MetaBall movement.
        private static double Angle1 = 0.0;
        private static double Angle2 = 0.0;
        private static double Angle3 = 0.0;
        
        private static BufferedImage logo = null;
        private static int logoX, logoY;
        
        private static boolean doDraw = false;
        
        // Create 3 MetaBalls.
        private METABALL[] mb = 
        {
            new METABALL(400,300,25),
            new METABALL(400,300,25),
            new METABALL(400,300,25),
            new METABALL(400,300,25),
            new METABALL(400,300,25)
        };
        
        // Constructor
        private DBuffer() {
            super();
            try {
                logo = ImageIO.read(new File("logo1.png"));
            } catch(IOException e){ }
            pt = new PTimer();
            difTime = 0;
        }

        // Do fun stuff here... :P
        public void updateBuffer() {
            // Update the FrameTimer.
            difTime = pt.update();
            
            // Update the Angle values.
            Angle1 += 0.001 * difTime;
            Angle2 += 0.0005 * difTime;
            Angle3 += 0.00025 * difTime;
            if( Angle1 >= 360.0 ) Angle1 -= 360.0;
            if( Angle2 >= 360.0 ) Angle2 -= 360.0;
            if( Angle3 >= 360.0 ) Angle3 -= 360.0;

            // Update MetaBall movement.
            mb[0].setX((int)(Math.cos(Angle1) * 325.0 + 400.0));
            mb[0].setY((int)(Math.sin(Angle2) * 75.0 + 300.0));
            mb[1].setX((int)(Math.cos(Angle2) * 300.0 + 400.0));
            mb[1].setY((int)(Math.sin(Angle3) * 100.0 + 300.0));
            mb[2].setX((int)(Math.cos(Angle3) * 275.0 + 400.0));
            mb[2].setY((int)(Math.sin(Angle1) * 125.0 + 300.0));
            mb[3].setX((int)(Math.cos(Angle3) * 150.0 + 400.0));
            mb[3].setY((int)(Math.sin(Angle3) * 75.0 + 300.0));
            mb[4].setX((int)(Math.cos(Angle3+180.0) * 150.0 + 400.0));
            mb[4].setY((int)(Math.sin(Angle3+180.0) * 75.0 + 300.0));
            
            logoX = (int)(Math.cos(Angle1) * 150.0 + 250.0);
            logoY = (int)(Math.sin(Angle1*2.0) * 30.0 + 15.0);
            
            doDraw = true;
            
            // Draw that shit! :)
            repaint();
        }
        
        // Override the paintBuffer method with own drawing stuff.
        @Override
        public void paintBuffer(Graphics g) {
            double sum;
            if(!doDraw) return;
            g.setColor(Color.decode("0x203040"));
            g.fillRect(0, 128, 799, 344);
            g.setColor(Color.WHITE);
            g.drawLine(0, 126, 799, 126);
            g.drawLine(0, 473, 799, 473);
            for(int y=128; y<472; y+=16) {
                for(int x=0; x<800; x+=16) {
                    sum = 0.0;
                    for(int i=0; i<METABALL.mCount; i++) {
                        sum += mb[i].Equation(x+7, y+7);
                    }
                    if(sum >= MIN_T && sum <= MAX_T) {
                        for(int y1=0; y1<16; y1+=2) {
                            for(int x1=0; x1<16; x1+=2) {
                                if(x+x1 < 800 && y+y1 < 472) {
                                    sum = 0.0;
                                    for(int i=0; i<METABALL.mCount; i++) {
                                        sum += mb[i].Equation(x+x1, y+y1);
                                    }
                                    if(sum >= MIN_THRESHOLD && sum <= MAX_THRESHOLD) {
                                        g.setColor(Color.decode("0x405060"));
                                        if(sum < MIN_THRESHOLD + 0.025) g.setColor(Color.decode("0x304050"));
                                        if(sum > MAX_THRESHOLD - 0.05) g.setColor(Color.decode("0x506070"));
                                        g.fillRect(x+x1, y+y1, 2, 2);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            g.drawImage(logo, logoX, logoY, this);
        }
    }
    
    // The MetaBall class.
    public static class METABALL {
        // Constructors
        private METABALL() {
            super();
            mX = 0;
            mY = 0;
            mR = 0;
            mCount++;
        }
        private METABALL(int x, int y, int radius) {
            super();
            mX = x;
            mY = y;
            mR = radius;
            mCount++;
        }

        // The all-powerfull Metaball equation. :D
        public double Equation(int x, int y) {
            double F = 0.0;
            return (mR / Math.sqrt( (x - mX)*(x - mX) + (y - mY)*(y - mY) ));
        }
        
        // Member variable access methods.
        public int x() { return mX; }
        public int y() { return mY; }
        public int r() { return mR; }
        public int getCount() { return mCount; }
        public void setX(int x) { mX = x; }
        public void setY(int y) { mY = y; }
        public void setR(int r) { mR = r; }
        
        // Member variables.
        private int mX;
        private int mY;
        private int mR;
        private static int mCount = 0;
    };
    
    // The main method.
    public static void main(String[] args) {
        // Create the main JFrame object.
        JFrame frame = new JFrame("MetaBalls v1.0");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(800, 600);
        frame.setLocation(100, 100);
        frame.setResizable(false);
        
        // Create a double-buffered canvas.
        DBuffer db = new DBuffer();
        db.setSize(800, 600);
        db.setBackground(Color.black);
        
        // Add the canvas to the frame and show it all.
        frame.getContentPane().add(db);
        frame.pack();
        frame.setVisible(true);

        PTimer pt = new PTimer();
        final long musicLength = 78000;
        long musicTimer = musicLength;
        long difTime = 0;
        
        MP3 mp3 = new MP3("Meta.mp3");
        mp3.play();
        
        while(true) {
            difTime = pt.update();
            musicTimer -= difTime;
            if( musicTimer <= 0 ) {
                mp3.close();
                mp3.play();
                musicTimer += musicLength;
            }
            db.updateBuffer();
        }
    }
}
